﻿using System;
using System.Collections.Generic;
using System.Xml;

namespace Kioskvalt.MidiSequencer
{
	public class PatternAutomation
	{
		public string ID;
		public int Channel;
		public string Macro;
		public List<PatternAutomationKey> Keys;
		public int LastValue;

		public PatternAutomation()
		{
			ID = "";
			Channel = 0;
			Macro = "";
			Keys = new List<PatternAutomationKey>();
		}

		public bool LoadFromXML(XmlNode node)
		{
			if (node.Attributes["id"] != null)
			{
				ID = node.Attributes["id"].Value;
			}

			if (node.Attributes["channel"] != null)
			{
				int i = 0;
				int.TryParse(node.Attributes["channel"].Value, out i);
				Channel = i;
			}

			if (node.Attributes["macro"] != null)
			{
				Macro = node.Attributes["macro"].Value;
			}


			XmlNodeList nl = node.SelectNodes("keys/key");
			if (nl != null)
				for (int j = 0; j < nl.Count; j++)
				{
					PatternAutomationKey pn = new PatternAutomationKey();
					if (pn.LoadFromXML(nl[j]))
						Keys.Add(pn);
				}

			return true;
		}
		public bool SaveToXML(XmlNode parent)
		{
			if (Keys.Count > 0)
			{
				SortKeys();

				XmlNode rootel = Utilities.AddXmlElement(parent, "automation");
				Utilities.AddXmlAttribute(rootel, "id", ID);
				Utilities.AddXmlAttribute(rootel, "channel", Channel.ToString());
				Utilities.AddXmlAttribute(rootel, "macro", Macro);

				XmlNode keysel = Utilities.AddXmlElement(rootel, "keys");
				for (int k = 0; k < Keys.Count; k++)
					Keys[k].SaveToXML(keysel);
			}
			return false;
		}

		public void SortKeys()
		{
			if (Keys.Count > 0)
				Keys.Sort(new PatternAutomationKeySorter());
		}

		public PatternAutomation Clone()
		{
			PatternAutomation ret = new PatternAutomation();
			ret.Channel = Channel;
			ret.ID = ID;
			for (int k = 0; k < Keys.Count; k++)
				ret.Keys.Add(Keys[k].Clone());
			return ret;
		}

		public PatternAutomationKey GetKeyIndex(int idx, bool clamp)
		{
			if (clamp)
			{
				if (idx < 0)
					idx = 0;
				if (idx > Keys.Count - 1)
					idx = Keys.Count - 1;
			}
			if (idx >= 0 && idx < Keys.Count)
				return Keys[idx];

			return null;

		}

		public float GetValueAt(float time)
		{
			PatternAutomationKey km1 = null;
			PatternAutomationKey k0 = null;
			PatternAutomationKey k1 = null;
			PatternAutomationKey kp1 = null;

			int baseidx = -1;
			for (int k = 0; k < Keys.Count; k++)
			{
				PatternAutomationKey ck = Keys[k];
				if (ck.Time <= time)
					baseidx = k;
			}

			km1 = GetKeyIndex(baseidx - 1, true);
			k0 = GetKeyIndex(baseidx, true);
			k1 = GetKeyIndex(baseidx + 1, true);
			kp1 = GetKeyIndex(baseidx + 2, true);

			if (k0 != null && k1 != null)
			{
				//	if (k0 == null && k1 != null)
				//		return k1.Value;

				//	if (k1 == null && k0 != null)
				//		return k0.Value;

				// interpolate

				float div = (float)(k1.Time - k0.Time);
				if (div < 1)
					div = 1;
				float dT = (float)(time - k0.Time) / div;
				float invdT = 1.0f - dT;
                
				return (dT * (float)k1.Value) + (invdT * (float)k0.Value);
				
				return k0.Value;
			}

			if( k0 != null )
				return k0.Value;

			return 0.0f;//  64.0f + 60.0f * (float)Math.Sin(time / 3.0f);
		}


	}
}
